package com.yami.shop.api.controller;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.yami.shop.bean.bo.PayInfoResultBO;
import com.yami.shop.bean.enums.PayEntry;
import com.yami.shop.bean.enums.PayStatus;
import com.yami.shop.bean.enums.ShopWithdrawCashStatus;
import com.yami.shop.bean.model.PayInfo;
import com.yami.shop.bean.model.ShopWithdrawCash;
import com.yami.shop.common.bean.RequestKitBean;
import com.yami.shop.common.enums.PayType;
import com.yami.shop.common.response.ResponseEnum;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.DateUtils;
import com.yami.shop.manager.impl.PayManager;
import com.yami.shop.service.PayInfoService;
import com.yami.shop.service.ShopWithdrawCashService;
import com.yami.shop.user.common.enums.UserBalanceWithdrawCashStateEnum;
import com.yami.shop.user.common.model.UserBalanceWithdrawCash;
import com.yami.shop.user.common.service.UserBalanceService;
import com.yami.shop.user.common.service.UserBalanceWithdrawCashService;
import com.yami.shop.user.common.service.UserGasLogService;
import com.yami.shop.user.common.service.UserLevelService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author LGH
 */
@Slf4j
@RestController
@RequestMapping("/notice/pay")
@Tag(name = "订单支付回调接口")
@AllArgsConstructor
public class PayNoticeController {
    private static final String REQ_CONTEXT_KEY_PARAMJSON = "REQ_CONTEXT_KEY_PARAMJSON";
    private final PayManager payManager;

    private final PayInfoService payInfoService;

    private final UserLevelService userLevelService;

    private final UserBalanceService userBalanceService;

    private final UserGasLogService userGasLogService;

    private final UserBalanceWithdrawCashService userBalanceWithdrawCashService;

    private final ShopWithdrawCashService shopWithdrawCashService;

    private final RequestKitBean requestKitBean;

    @Operation(summary = "支付异步回调", description = "支付异步回调")
    @RequestMapping("/{payEntry}/{payType}")
    public Object notice(HttpServletRequest request, @PathVariable("payEntry") Integer payEntry, @PathVariable("payType") Integer payType, @RequestBody(required = false) String data) throws WxPayException, UnsupportedEncodingException, AlipayApiException {
        log.info("支付回调已完成处理");
        PayInfoResultBO payInfoResultBO = payManager.validateAndGetPayInfo(request, PayType.instance(payType), data);

        // 校验订单参数异常
        if (!payInfoResultBO.getIsPaySuccess()) {
            return ServerResponseEntity.success(null);
        }

        PayInfo payInfo = payInfoService.getOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayNo, payInfoResultBO.getPayNo()));

        // 已经支付
        if (Objects.equals(payInfo.getPayStatus(), PayStatus.PAYED.value()) || Objects.equals(payInfo.getPayStatus(), PayStatus.REFUND.value())) {
            return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
        }
        // 支付金额不对
        if (!Objects.equals(payInfo.getPayAmount(), payInfoResultBO.getPayAmount()) && !Objects.equals(payInfo.getPayType(), PayType.PAYPAL.value())) {
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }
        ServerResponseEntity<String> stringServerResponseEntity;
        if (Objects.equals(payEntry, PayEntry.ORDER.value())) {
            stringServerResponseEntity = payInfoService.noticeOrder(payInfoResultBO, payInfo);
            PayType payTypeEnum = PayType.instance(payType);
            if (PayType.isHnaPay(payTypeEnum)){
                if (stringServerResponseEntity.getCode().equals(ResponseEnum.OK.value())) {
                    return "200";
                }
            }else {
                return stringServerResponseEntity;
            }
        } else if (Objects.equals(payEntry, PayEntry.RECHARGE.value())) {
            stringServerResponseEntity = userBalanceService.noticeRecharge(payInfoResultBO, payInfo);
            PayType payTypeEnum = PayType.instance(payType);
            if (PayType.isHnaPay(payTypeEnum)){
                if (stringServerResponseEntity.getCode().equals(ResponseEnum.OK.value())) {
                    return "200";
                }
            }else {
                return stringServerResponseEntity;
            }
        } else if (Objects.equals(payEntry, PayEntry.VIP.value())) {
            stringServerResponseEntity = userLevelService.noticeBuyVip(payInfoResultBO, payInfo);
            PayType payTypeEnum = PayType.instance(payType);
            if (PayType.isHnaPay(payTypeEnum)){
                if (stringServerResponseEntity.getCode().equals(ResponseEnum.OK.value())) {
                    return "200";
                }
            }else {
                return stringServerResponseEntity;
            }
        } else if (Objects.equals(payEntry, PayEntry.RED_ENVELOPE.value())) {
            stringServerResponseEntity = userBalanceService.noticeRedEnvelope(payInfoResultBO, payInfo);
            PayType payTypeEnum = PayType.instance(payType);
            if (PayType.isHnaPay(payTypeEnum)){
                if (stringServerResponseEntity.getCode().equals(ResponseEnum.OK.value())) {
                    return "200";
                }
            }else {
                return stringServerResponseEntity;
            }
        } else if (Objects.equals(payEntry, PayEntry.GAS_RECHARGE.value())) {
            stringServerResponseEntity = userGasLogService.noticeGasRecharge(payInfoResultBO, payInfo);
            PayType payTypeEnum = PayType.instance(payType);
            if (PayType.isHnaPay(payTypeEnum)){
                if (stringServerResponseEntity.getCode().equals(ResponseEnum.OK.value())) {
                    return "200";
                }
            }else {
                return stringServerResponseEntity;
            }
        }
        return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
    }

    @RequestMapping(value = "/callBack", method = {RequestMethod.POST, RequestMethod.GET})
    @Operation(summary = "银联支付异步回调", description = "银联支付异步回调")
    @ResponseBody
    public ServerResponseEntity<Map<String, String>> unionPayCall(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return ServerResponseEntity.success(params);
    }

    /**
     * 提现打款异步通知
     *
     * @param request 异步通知数据
     */
    @PostMapping("/balanceWithdrawCash/{withdrawCashId}")
    @Operation(summary = "提现打款异步通知", description = "提现打款异步通知")
    String auditNotice(HttpServletRequest request, @PathVariable("withdrawCashId") String withdrawCashId) {
        JSONObject reqParamJSON = requestKitBean.getReqParamJSON();
        log.info("提现打款异步通知解析数据为：reqParamJSON:{}", JSONObject.toJSONString(reqParamJSON));
        String resultCode = reqParamJSON.getString("resultCode"); // 处理结果码
        String errorCode = reqParamJSON.getString("errorCode"); // 异常代码
        String errorMsg = reqParamJSON.getString("errorMsg"); // 异常描述
        String ncountOrderId = reqParamJSON.getString("ncountOrderId"); // 订单号
        if (resultCode.equals("0000")) {
            UserBalanceWithdrawCash userBalanceWithdrawCash = userBalanceWithdrawCashService.getById(Long.valueOf(withdrawCashId));
            userBalanceWithdrawCash.setState(UserBalanceWithdrawCashStateEnum.CASH_SUCCESS.getValue());
            userBalanceWithdrawCash.setMerchantOrderId(ncountOrderId);
            userBalanceWithdrawCashService.updateById(userBalanceWithdrawCash);
        } else {
            log.error("提现失败{}，{}", errorCode, errorMsg);
        }
        return "200";
    }


    /**
     * 提现打款异步通知
     *
     * @param request 异步通知数据
     */
    @PostMapping("/shopWithdrawCash/{withdrawCashId}")
    @Operation(summary = "店铺提现打款异步通知", description = "店铺提现打款异步通知")
    String shopAuditNotice(HttpServletRequest request, @PathVariable("withdrawCashId") String withdrawCashId) {
        JSONObject reqParamJSON = requestKitBean.getReqParamJSON();
        log.info("提现打款异步通知解析数据为：reqParamJSON:{}", JSONObject.toJSONString(reqParamJSON));
        String resultCode = reqParamJSON.getString("resultCode"); // 处理结果码
        String errorCode = reqParamJSON.getString("errorCode"); // 异常代码
        String errorMsg = reqParamJSON.getString("errorMsg"); // 异常描述
        String ncountOrderId = reqParamJSON.getString("ncountOrderId"); // 订单号
        if (resultCode.equals("0000")) {
            ShopWithdrawCash shopWithdrawCash = shopWithdrawCashService.getById(Long.valueOf(withdrawCashId));
            shopWithdrawCash.setStatus(ShopWithdrawCashStatus.PAYSUCCESS.value()); // 已打款
            shopWithdrawCash.setPayingTime(DateUtils.dateToStrYmd(new Date()));
            shopWithdrawCash.setUpdateTime(new Date());
            shopWithdrawCash.setBankOrderId(ncountOrderId);
            shopWithdrawCashService.updateById(shopWithdrawCash);
        } else {
            log.error("提现失败{}，{}", errorCode, errorMsg);
        }
        return "200";
    }

}
